<?php

namespace app\admin\controller\api;

use app\admin\model\AuthGroup;
use app\admin\model\AuthGroupAccess;
use app\common\model\School;
use fast\Tree;
use GuzzleHttp\Client;
use Monolog\Handler\IFTTTHandler;
use think\Controller;
use think\Db;
use think\exception\HttpResponseException;
use think\Log;
use think\Request;
use think\Response;

/**
 * 后台api基类
 *
 * @internal
 */
class Api extends Controller
{
    /**
     * @var Request Request 实例
     */
    protected $request;

    /**
     * @var bool 验证失败是否抛出异常
     */
    protected $failException = false;

    /**
     * @var bool 是否批量验证
     */
    protected $batchValidate = false;

    /**
     * @var array 前置操作方法列表
     */
    protected $beforeActionList = [];

    /**
     * 无需登录的方法,同时也就不需要鉴权了
     * @var array
     */
    protected $noNeedLogin = [];

    /**
     * 无需鉴权的方法,但需要登录
     * @var array
     */
    protected $noNeedRight = [];

    /**
     * 默认响应输出类型,支持json/xml
     * @var string
     */
    protected $responseType = 'json';

    protected $_user = null;

    /**
     * 构造方法
     * @access public
     * @param Request $request Request 对象
     */
    public function __construct(Request $request = null)
    {
        $this->request = is_null($request) ? Request::instance() : $request;

        // 控制器初始化
        $this->_initialize();
    }

    public function _initialize()
    {
        if (isset($_SERVER['HTTP_ORIGIN'])) {
            header("Access-Control-Allow-Origin: " . $this->request->server('HTTP_ORIGIN'));
            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Max-Age: 86400');
        }
        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
            }
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
            }
        }

        $access_token = $this->request->request('access_token');

        if ($access_token && 'suzhiok' != $access_token) {
            $client = new Client([
                'base_uri' => config('sso.server'),
                'timeout' => 30,
                'allow_redirects' => true
            ]);
            $response = $client->request('POST', '?command=userInfo', [
                'form_params' => [
                    'access_token' => $access_token,
                ]
            ]);

            $code = $response->getStatusCode();
            if (200 == $code) {
                $body = $response->getBody();
                if ($body->getSize()) {
                    $contents = $body->getContents();
                    $this->_user = json_decode($contents, true);
                }
            } else {
                $this->error('未登录');
            }

        }

        if ($this->match($this->noNeedLogin)) {
            if ('suzhiok' != $access_token) {
                $this->error('未登录');
            }
        } else if (!$this->_user) {
            $this->error('未登录');
        }

//        // 检测是否需要验证登录
//        if (!$this->match($this->noNeedLogin) && !$this->_user) {
//            $this->error('未登录');
//        }

    }

    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    public function match($arr = [])
    {
        $request = Request::instance();
        $arr = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr) {
            return false;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) {
            return true;
        }

        // 没找到匹配
        return false;
    }

    /**
     * 操作成功返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为1
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 操作失败返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 返回封装后的 API 数据到客户端
     * @access protected
     * @param mixed $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型，支持json/xml/jsonp
     * @param array $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    protected function result($msg, $data = null, $code = 0, $type = null, array $header = [])
    {
        $result = [
            'code' => $code,
            'msg' => $msg,
            'time' => Request::instance()->server('REQUEST_TIME'),
            'data' => $data,
        ];
        // 如果未设置类型则自动判断
        $type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType);

        if (isset($header['statuscode'])) {
            $code = $header['statuscode'];
            unset($header['statuscode']);
        } else {
            //未设置状态码,根据code值判断
            $code = $code >= 1000 || $code < 200 ? 200 : $code;
        }
        $response = Response::create($result, $type, $code)->header($header);
        throw new HttpResponseException($response);
    }

    public function getChildrenGroupIds($withself = false)
    {
        //取出当前管理员所有的分组
        $groups = $this->getGroups();

        $groupIds = [];
        foreach ($groups as $k => $v) {
            $groupIds[] = $v['id'];
        }
        // 取出所有分组
        $groupList = AuthGroup::where(['status' => 'normal'])->select();
        $objList = [];
        foreach ($groups as $K => $v) {
            if ($v['rules'] === '*') {
                $objList = $groupList;
                break;
            }
            // 取出包含自己的所有子节点
            $childrenList = Tree::instance()->init($groupList)->getChildren($v['id'], true);
            $obj = Tree::instance()->init($childrenList)->getTreeArray($v['pid']);
            $objList = array_merge($objList, Tree::instance()->getTreeList($obj));
        }
        $childrenGroupIds = [];
        foreach ($objList as $k => $v) {
            $childrenGroupIds[] = $v['id'];
        }
        if (!$withself) {
            $childrenGroupIds = array_diff($childrenGroupIds, $groupIds);
        }
        return $childrenGroupIds;
    }
    public function getGroups($uid = null)
    {
        $uid = is_null($uid) ? $this->_user['id'] : $uid;
        static $groups = [];
        if (isset($groups[$uid])) {
            return $groups[$uid];
        }

        // 执行查询
        $user_groups = Db::name('auth_group_access')
            ->alias('aga')
            ->join('__' . strtoupper('auth_group') . '__ ag', 'aga.group_id = ag.id', 'LEFT')
            ->field('aga.uid,aga.group_id,ag.id,ag.pid,ag.name,ag.rules,ag.schools')
            ->where("aga.uid='{$uid}' and ag.status='normal'")
            ->select();
        $groups[$uid] = $user_groups ?: [];
        return $groups[$uid];
    }
    public function getGroupIds($uid = null)
    {
        $groups = $this->getGroups($uid);
        $groupIds = [];
        foreach ($groups as $K => $v) {
            $groupIds[] = (int)$v['group_id'];
        }
        return $groupIds;
    }
    public function isSuperAdmin()
    {
        return in_array('*', $this->getRuleIds()) ? true : false;
    }
    public function getRuleIds($uid = null)
    {
        $uid = is_null($uid) ? $this->_user['id'] : $uid;
        //读取用户所属用户组
        $groups = $this->getGroups($uid);
        $ids = []; //保存用户所属用户组设置的所有权限规则id
        foreach ($groups as $g) {
            $ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
        }
        $ids = array_unique($ids);
        return $ids;
    }

    public function getSchools($uid = null)
    {
        $uid = is_null($uid) ? $this->id : $uid;

        static $schools = [];
        if (isset($schools[$uid])) {
            return $schools[$uid];
        }

        $schoolIds = $this->getSchoolIds($uid);
        $schoolList = School::whereIn("id", $schoolIds)->select();
        $schools[$uid] = $schoolList ?: [];
        return $schools[$uid];
    }
    public function getSchoolIds($uid = null)
    {
        $uid = is_null($uid) ? $this->_user['id'] : $uid;
        //读取用户所属用户组
        $groups = $this->getGroups($uid);

        $ids = []; //保存用户所属用户组设置的所有权限规则id
        foreach ($groups as $g) {
            $ids = array_merge($ids, explode(',', trim($g['schools'], ',')));
        }
        $ids = array_unique($ids);
        return $ids;
    }
    public function getChildrenSchoolIds($withself = false)
    {
        //取出当前管理员所有的分组
        $groups = $this->getGroups();
        $schoolIds = []; //保存用户所属用户组设置的所有权限规则id
        foreach ($groups as $g) {
            $schoolIds = array_merge($schoolIds, explode(',', trim($g['schools'], ',')));
        }
        $schoolIds = array_unique($schoolIds);

        $schoolList = \app\common\model\School::where(['status' => 'normal'])->select();

        $schoolRow = collection($schoolList)->toArray();
        $schoolData = [];
        foreach ($schoolRow as $key => $value) {
            $schoolData[$value['id']] = $value;
        }

        $objList = [];
        foreach ($schoolIds as $K => $v) {
            if ($v === '*') {
                $objList = $schoolList;
                break;
            }

            if (isset($schoolData[$v])) {
                $childrenList = Tree::instance()->init($schoolList)->getChildren($v, true);
                $obj = Tree::instance()->init($childrenList)->getTreeArray($schoolData[$v]['pid']);
                $objList = array_merge($objList, Tree::instance()->getTreeList($obj));
            }
        }

        $childrenSchoolIds = [];
        foreach ($objList as $k => $v) {
            $childrenSchoolIds[] = $v['id'];
        }

        if (!$withself) {
            $childrenSchoolIds = array_diff($childrenSchoolIds, [$this->_user['school_id']]);
        }

        return array_unique($childrenSchoolIds);
    }

    /**
     * 快速搜索时执行查找的字段
     */
    protected $searchFields = 'id';


    /**
     * 生成查询所需要的条件,排序方式
     * @param mixed   $searchfields   快速查询的字段
     * @param boolean $relationSearch 是否关联查询
     * @return array
     */
    protected function buildparams($searchfields = null, $relationSearch = null)
    {
        $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
        $search = $this->request->request("search", '');
        $filter = $this->request->request("filter", '');
        $op = $this->request->request("op", '', 'trim');
        $sort = $this->request->request("sort",  'id');
        $order = $this->request->request("order", "DESC");
        $offset = $this->request->request("offset", 0);
        $limit = $this->request->request("limit", 0);
        $filter = (array)json_decode($filter, true);
        $op = (array)json_decode($op, true);
        $filter = $filter ? $filter : [];
        $where = [];
        $tableName = '';
        if ($search) {
            $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
            foreach ($searcharr as $k => &$v) {
                $v = stripos($v, ".") === false ? $tableName . $v : $v;
            }
            unset($v);
            $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
        }
        foreach ($filter as $k => $v) {
            $sym = isset($op[$k]) ? $op[$k] : '=';
            if (stripos($k, ".") === false) {
                $k = $tableName . $k;
            }
            $v = !is_array($v) ? trim($v) : $v;
            $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
            switch ($sym) {
                case '=':
                case '<>':
                    $where[] = [$k, $sym, (string)$v];
                    break;
                case 'LIKE':
                case 'NOT LIKE':
                case 'LIKE %...%':
                case 'NOT LIKE %...%':
                    $where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
                    break;
                case '>':
                case '>=':
                case '<':
                case '<=':
                    $where[] = [$k, $sym, intval($v)];
                    break;
                case 'FINDIN':
                case 'FINDINSET':
                case 'FIND_IN_SET':
                    $where[] = "FIND_IN_SET('{$v}', " . ($relationSearch ? $k : '`' . str_replace('.', '`.`', $k) . '`') . ")";
                    break;
                case 'IN':
                case 'IN(...)':
                case 'NOT IN':
                case 'NOT IN(...)':
                    $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
                    break;
                case 'BETWEEN':
                case 'NOT BETWEEN':
                    $arr = array_slice(explode(',', $v), 0, 2);
                    if (stripos($v, ',') === false || !array_filter($arr)) {
                        continue 2;
                    }
                    //当出现一边为空时改变操作符
                    if ($arr[0] === '') {
                        $sym = $sym == 'BETWEEN' ? '<=' : '>';
                        $arr = $arr[1];
                    } elseif ($arr[1] === '') {
                        $sym = $sym == 'BETWEEN' ? '>=' : '<';
                        $arr = $arr[0];
                    }
                    $where[] = [$k, $sym, $arr];
                    break;
                case 'RANGE':
                case 'NOT RANGE':
                    $v = str_replace(' - ', ',', $v);
                    $arr = array_slice(explode(',', $v), 0, 2);
                    if (stripos($v, ',') === false || !array_filter($arr)) {
                        continue 2;
                    }
                    //当出现一边为空时改变操作符
                    if ($arr[0] === '') {
                        $sym = $sym == 'RANGE' ? '<=' : '>';
                        $arr = $arr[1];
                    } elseif ($arr[1] === '') {
                        $sym = $sym == 'RANGE' ? '>=' : '<';
                        $arr = $arr[0];
                    }
                    $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' time', $arr];
                    break;
                case 'LIKE':
                case 'LIKE %...%':
                    $where[] = [$k, 'LIKE', "%{$v}%"];
                    break;
                case 'NULL':
                case 'IS NULL':
                case 'NOT NULL':
                case 'IS NOT NULL':
                    $where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
                    break;
                default:
                    break;
            }
        }
        $where = function ($query) use ($where) {
            foreach ($where as $k => $v) {
                if (is_array($v)) {
                    call_user_func_array([$query, 'where'], $v);
                } else {
                    $query->where($v);
                }
            }
        };
        return [$where, $sort, $order, $offset, $limit];
    }

}